package com.efast.cafe.commponent.statemach.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.efast.cafe.framework.constant.CommonConstant;
import com.efast.cafe.framework.enums.ResultStatus;
import com.efast.cafe.framework.exception.ServiceException;
import com.efast.cafe.framework.redis.ObjectRedisTemplate;
import com.efast.cafe.framework.util.SpringWebUtils;
import com.efast.cafe.portal.bean.company.PortalCompanyUserBean;
import com.efast.cafe.portal.bean.statemach.PortalStateMachConfBean;
import com.efast.cafe.portal.bean.statemach.PortalStateMachField;
import com.efast.cafe.portal.bean.statemach.PortalStateMachHandleBean;
import com.efast.cafe.portal.bean.statemach.PortalStateMachHandleJs;
import com.efast.cafe.portal.bean.statemach.PortalStateMachNoticeBean;
import com.efast.cafe.portal.bean.statemach.PortalStateMachStateBean;
import com.efast.cafe.commponent.statemach.bean.StateAuths;
import com.efast.cafe.commponent.statemach.bean.StateExtData;
import com.efast.cafe.commponent.statemach.dao.PortalStateMachDao;
import com.efast.cafe.portal.entity.base.PortalBaseLov;
import com.efast.cafe.portal.entity.base.PortalBaseParameter;
import com.efast.cafe.portal.remote.common.EntityInfoQueryService;
import com.efast.cafe.portal.remote.common.LovService;
import com.efast.cafe.portal.remote.statemach.PortalStatemachFieldAuthService;
import com.efast.cafe.util.ConfigUtil;
import com.efast.cafe.commponent.statemach.service.IPortalStateMachService;

@Service
@Transactional
public class PortalStateMachServiceImpl implements IPortalStateMachService {

	@Autowired
	private EntityInfoQueryService queryService;

	@Autowired
	private LovService lovService;

	@Autowired
	private ObjectRedisTemplate objectRedisTemplate;

	@Autowired
	private PortalStateMachDao portalStateMachDao;
	@Autowired
	private PortalStatemachFieldAuthService portalStatemachFieldAuthService;

	/**
	 * 日志
	 */
	// protected static ExtLogger log =
	// ExtLoggerCommon.getLogger(PortalStateMachServiceImpl.class);

	/**
	 * 获取状态机配置
	 * 
	 * @param confId
	 */
	@Override
	public PortalStateMachConfBean getPortalStateMachByConfId(Long confId) {
		ValueOperations<String, Object> redisValueObj = objectRedisTemplate.opsForValue();
		// Object object = null;
		Object object = redisValueObj.get(CommonConstant.REDIS_STATEMACH_CONFID_ + confId);
		PortalStateMachConfBean _pSMBean = new PortalStateMachConfBean();
		JSONArray ress = new JSONArray();
		if (null == object) {
			// PortalStateMachConfBean _pSMBean = new PortalStateMachConfBean();
			PortalStateMachConfBean conf = portalStateMachDao.queryConfById(confId);
			List<PortalStateMachStateBean> stateList = portalStateMachDao.queryStateListByConfId(confId);
			for (int i = 0; i < stateList.size(); i++) {
				if (stateList.get(i).getResource() != null) {
					PortalBaseParameter pp = new PortalBaseParameter();
					pp.setParam_key("fms_resource_ext");
					List<PortalBaseLov> lov = lovService.api_getNextNodeLov(pp);
					for (String resName : JSON.parseObject(stateList.get(i).getResource()).getString("resName")
							.split(",")) {
						for (PortalBaseLov l : lov) {
							if (l.getOption_key().equals(resName)) {
								JSONObject res = new JSONObject();
								res.put("key", resName);
								res.put("value", l.getOption_desc());
								ress.add(res);
							}
						}
					}
				}
				List<PortalStateMachHandleBean> handleList = portalStateMachDao.queryHandleListByRel(confId,
						stateList.get(i).getId());
				List<PortalStateMachNoticeBean> noticeList = portalStateMachDao.queryNoticeListByStateId(confId,
						stateList.get(i).getId());
				stateList.get(i).setHeadle(handleList);
				stateList.get(i).setNotice(noticeList);
			}
			_pSMBean.setStateMachState(stateList);
			_pSMBean.setId(conf.getId());
			_pSMBean.setConfName(conf.getConfName());
			_pSMBean.setBeginState(conf.getBeginState());
			_pSMBean.setEndState(conf.getEndState());
			_pSMBean.setExtResource(ress);
			_pSMBean.setParallelLock(conf.getParallelLock());
			redisValueObj.set(CommonConstant.REDIS_STATEMACH_CONFID_ + confId, _pSMBean);
		} else {
			_pSMBean = (PortalStateMachConfBean) object;
		}
		return _pSMBean;
	}

	@Override
	public void ChangeState(Long Id, Long stateId) {
		// _stateMachManager.ChangeState(Id, stateId);
	}

	// @Override
	// public void AddChangeStateListener(ChangeStateListener listener) {
	// _stateMachManager.addChangeStateListener(listener);
	// }

	/**
	 * 根据业务流程ID和状态ID获取扩展
	 * 
	 * @param confId
	 * @param stateId
	 */
	@Override
	public StateExtData GetStateExtDataByConfid(Long confId, Long stateId) {
		PortalStateMachConfBean confBean = getPortalStateMachByConfId(confId);
		PortalStateMachStateBean thisStateBean = null;
		if (stateId > 0) {
			for (int i = 0; i < confBean.getStateMachState().size(); i++) {
				if (confBean.getStateMachState().get(i).getId().equals(stateId)) {
					thisStateBean = confBean.getStateMachState().get(i);
				}
			}
		} else {
			// 获取第一个状态
			for (int i = 0; i < confBean.getStateMachState().size(); i++) {
				if (confBean.getStateMachState().get(i).getId().equals(confBean.getBeginState())) {
					thisStateBean = confBean.getStateMachState().get(i);
				}
			}
		}
		StateExtData ret = new StateExtData();
		if (thisStateBean != null) {
			if (thisStateBean.getExtForm() != null) {
				ret.setExtForm(queryService.queryEntityInfo(thisStateBean.getExtForm()));
			}
			if (thisStateBean.getResource() != null) {
				// List<PortalBaseLov> lov =
				// lovService.getNextNodeLov("fms_resource_ext");
				// JSONArray ress = new JSONArray();
				// for (String resName :
				// JSON.parseObject(thisStateBean.getResource()).getString("resName").split(","))
				// {
				// for (PortalBaseLov l : lov) {
				// if (l.getOption_key().equals(resName)) {
				// JSONObject res = new JSONObject();
				// res.put("key", resName);
				// res.put("value", l.getOption_desc());
				// ress.add(res);
				// }
				// }
				// }
				// ret.setResource(ress);

				// task上的ResType优先，这里也可以配，task上没有则用这里的
				ret.setResType(JSON.parseObject(thisStateBean.getResource()).getString("resType"));
			}
			ret.setResource(confBean.getExtResource());
			if (thisStateBean.getHeadle().size() > 0) {
				ret.setHandles(thisStateBean.getHeadle());
			}
			ret.setViewCode(thisStateBean.getViewCode());
			Map<String, List<String>> map = portalStatemachFieldAuthService.queryFieldAuthBy(confId.intValue(), stateId.intValue(), null);
			List<String> actions = map.get("actions");
			List<String> toolbars = map.get("toolbars");
			List<String> invisibles = map.get("invisibles");
			List<String> non_editables =  map.get("non_editables");
			List<String> required = map.get("required");
			StateAuths stateAuths = new StateAuths();
			stateAuths.setRequired(required);
			stateAuths.setActions(actions);
			stateAuths.setInvisibles(invisibles);
			stateAuths.setNonEditables(non_editables);;
			stateAuths.setToolbars(toolbars);
			ret.setViewAuth(stateAuths);
		}
		return ret;
	}

	/**
	 * 获取初始化状态
	 * 
	 * @param confId
	 * @return
	 */
	@Override
	public PortalStateMachStateBean getInitState(Long confId) {
		PortalStateMachConfBean portalStateMachBean = this.getPortalStateMachByConfId(confId);
		PortalStateMachStateBean thisStateBean = new PortalStateMachStateBean();
		for (int i = 0; i < portalStateMachBean.getStateMachState().size(); i++) {
			if (portalStateMachBean.getStateMachState().get(i).getId().equals(portalStateMachBean.getBeginState())) {
				thisStateBean = portalStateMachBean.getStateMachState().get(i);
			}
		}
		return thisStateBean;
	}

	/**
	 * 获取当前状态实例
	 * 
	 * @param confId
	 * @param stateId
	 * @return
	 */
	@Override
	public PortalStateMachStateBean getCurrentState(Long confId, Long stateId) {
		PortalStateMachConfBean portalStateMachBean = this.getPortalStateMachByConfId(confId);
		PortalStateMachStateBean thisStateBean = new PortalStateMachStateBean();
		thisStateBean.setParallelLock(portalStateMachBean.getParallelLock());
		// 获取条件
		for (int i = 0; i < portalStateMachBean.getStateMachState().size(); i++) {
			if (portalStateMachBean.getStateMachState().get(i).getId().equals(stateId)) {
				thisStateBean = portalStateMachBean.getStateMachState().get(i);
			}
		}
		return thisStateBean;
	}

	/**
	 * 根据Json参数返回应该执行的Handle
	 * 
	 * @param thisHandle
	 * @param json
	 * @return
	 * @throws ScriptException
	 */
	@Override
	public PortalStateMachHandleBean getExecHandle(List<PortalStateMachHandleBean> thisHandle, String json){
		PortalStateMachHandleBean execHandle = new PortalStateMachHandleBean();
		// 遍历条件
		ScriptEngineManager manager = new ScriptEngineManager();
		ScriptEngine engine = manager.getEngineByName("JavaScript");

		for (int j = 0; j < thisHandle.size(); j++) {
			// String js = "{\"para\": [\"url\"],\"js\":
			// \"url.indexOf('/assign')!=-1\"}";
			String js = thisHandle.get(j).getHandleUrl();
			PortalStateMachHandleJs hjs = JSON.parseObject(js, PortalStateMachHandleJs.class);
			// 条件表达式输入参数，参数来源于json
			for (String p : hjs.getPara()) {
				//如果p包含.在扩展里找，如果不包含.在主属性里找
				if (!p.contains(".")) {
					engine.put(p, JSON.parseObject(json).getString(p));
				}
				else{
					String ps[] = p.split("\\.");
					if (JSON.parseObject(json).containsKey("extFormData")
							&& JSON.parseObject(json).getJSONObject("extFormData").containsKey(ps[0])) {
						engine.put(ps[1], JSON.parseObject(json).getJSONObject("extFormData").getJSONObject(ps[0])
								.getString(ps[1]));
					}
					else{
						engine.put(ps[1],"");
					}
				}
			}

			boolean result=false;
			try {
				result = (boolean) engine.eval(hjs.getJs());
			} catch (ScriptException e) {
				throw new ServiceException(ResultStatus.SYS_ERROR.getCode());
			}
			if (result) {
				execHandle = thisHandle.get(j);
			}
		}
		return execHandle;
	}

	/**
	 * 获取最后一个状态
	 */
	@Override
	public boolean isLastState(Long confId, Long stateid) {
		boolean ret = false;
		PortalStateMachConfBean portalStateMachBean = this.getPortalStateMachByConfId(confId);
		if (portalStateMachBean.getEndState().equals(stateid)) {
			ret = true;
		}
		return ret;
	}

	/**
	 * 获取要发送的消息配置
	 * 
	 * @param confId
	 * @param changeState
	 * @param json
	 * @return
	 */
	@Override
	public List<PortalStateMachNoticeBean> getNoticeConfig(Long confId, Long changeState, String json) {
		try {
			// 要发送的消息配置
			List<PortalStateMachNoticeBean> sendNoticeList = new ArrayList<PortalStateMachNoticeBean>();
			// 获取noticeList(状态上的消息配置)
			List<PortalStateMachNoticeBean> noticeList = this.getCurrentState(confId, changeState).getNotice();
			JSONObject paraJson = JSON.parseObject(json);
			if (noticeList == null) {
				return null;
			}
			ScriptEngineManager manager = new ScriptEngineManager();
			ScriptEngine engine = manager.getEngineByName("JavaScript");
			for (int j = 0; j < noticeList.size(); j++) {
				String strjs = noticeList.get(j).getSendLogic();
				PortalStateMachHandleJs hjs = JSON.parseObject(strjs, PortalStateMachHandleJs.class);
				for (String p : hjs.getPara()) {
					if (!p.contains(".")) {
						engine.put(p, paraJson.getString(p));
					} else if (paraJson.containsKey("extFormData")) {
						String ps[] = p.split("\\.");
						engine.put(ps[1], paraJson.getJSONObject("extFormData").getJSONObject(ps[0]).getString(ps[1]));
					}
				}
				boolean result = (boolean) engine.eval(hjs.getJs());// 如果js交验为true则加入发送列表
				if (result) {
					sendNoticeList.add(noticeList.get(j));
				}
			}
			return sendNoticeList;
		} catch (Exception e) {
			// log.error("fms解析消息配置失败", e);
			return null;
		}
	}

	/**
	 * 根据通知配置获取人员
	 * 
	 * @param ParaKey
	 * @param id
	 * @param companyCode
	 * @return
	 */
	@Override
	public PortalCompanyUserBean getCompanyUserBeanForNotice(String ParaKey, String id, String companyCode) {
		String[] paras = ParaKey.split("\\.");
		return portalStateMachDao.getCompanyUserBeanForNotice(paras[1], paras[0], id, companyCode);
	}

	@Override
	public Long getState(Long id) {
		return portalStateMachDao.getState(id);
	}

	@Override
	public List<PortalStateMachField> getFieldForStateMach(Long confId, Long stateId, String entityName) {
		return portalStateMachDao.getFieldForStateMach(confId, stateId, entityName,
				SpringWebUtils.getRequestCompany(), ConfigUtil.getSystemVersion(), ConfigUtil.getSystemIndentifier());
	}
}
